package pri.damai.xiaowu.common.core.tree;

import cn.hutool.core.collection.CollectionUtil;
import pri.damai.xiaowu.common.core.tree.node.BaseTreeNode;
import pri.damai.xiaowu.common.core.tree.node.FullTreeNode;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author DaMai
 * @Description:
 * @Date 2020/2/19 22:04
 */
public class TreeUtils {

    /** 顶级节点 */
    public static final Long TOP_PARENT_ID = 0L;

    public static <T extends BaseTreeNode<T>> List<T> toTreeNonRecursion(List<T> list, Long topId) {

        // key:parentId; value: nodeList
        Map<Long, List<T>> tMap = list.stream()
                .collect(Collectors.groupingBy(BaseTreeNode::getParentId, Collectors.toList()));

        // 顶级节点
        List<T> topMenuList = tMap.get(topId);

        // 树化
        List<T> temp = topMenuList;
        while (CollectionUtil.isNotEmpty(temp)) {

            List<T> level = new ArrayList<>();
            for (T t : temp) {
                List<T> tChildren = tMap.get(t.getId());
                t.setChildren(tChildren);
                if (tChildren != null) {
                    level.addAll(tChildren);
                }
            }

            temp = level;
        }

        return topMenuList;
    }

    public static <T extends FullTreeNode<T>> List<T> toSortTree(List<T> list, Long topId) {
        // key:parentId; value: nodeList
        Map<Long, List<T>> tMap = list.stream()
                .sorted(Comparator.comparingInt(FullTreeNode::getSortOrder))
                .collect(Collectors.groupingBy(BaseTreeNode::getParentId, Collectors.toList()));

        // 顶级节点
        List<T> topMenuList = tMap.get(topId);

        // 树化
        List<T> temp = topMenuList;
        while (CollectionUtil.isNotEmpty(temp)) {

            List<T> level = new ArrayList<>();
            for (T t : temp) {
                List<T> tChildren = tMap.get(t.getId());
                t.setChildren(tChildren);
                if (tChildren != null) {
                    level.addAll(tChildren);
                }
            }

            temp = level;
        }

        //

        return topMenuList;
    }

    /**
     * 转换为树形
     * @param list 所有节点
     * @return 转换后的树结构菜单
     */
    public static <T extends BaseTreeNode<?>> List<T> toTree(List<T> list, Long patentId) {
        // 最初, 所有的 "菜单" 都是待用的
        List<BaseTreeNode<?>> all = new ArrayList<>(list);

        // 拿到所有的顶级 "菜单",后续以顶级菜单为基础,向下递归。
        List<T> roots = new ArrayList<>();
        for (BaseTreeNode<?> menuDTO : list) {
            if (menuDTO.getParentId().equals(patentId)) {
                roots.add((T) menuDTO);
            }
        }

        // 将所有顶级菜单从 "待用菜单列表" 中删除
        all.removeAll(roots);

        roots.forEach(m -> m.setChildren(getCurrentNodeChildren(m, all)));

        return roots;
    }

    public static <T extends BaseTreeNode<?>> List<T> parallelToTree(List<T> list, Long patentId) {
        // 最初, 所有的 "菜单" 都是待用的
        List<BaseTreeNode<?>> all = new ArrayList<>(list);

        // 拿到所有的顶级 "菜单",后续以顶级菜单为基础,向下递归。
        List<T> roots = new ArrayList<>();
        for (BaseTreeNode<?> menuDTO : list) {
            if (menuDTO.getParentId().equals(patentId)) {
                roots.add((T) menuDTO);
            }
        }

        // 将所有顶级菜单从 "待用菜单列表" 中删除
        all.removeAll(roots);

        roots.parallelStream().forEach(m -> m.setChildren(getCurrentNodeChildren(m, all)));

        return roots;
    }

    /**
     * 递归函数
     *      递归目的: 拿到子节点
     *      递归终止条件: 没有子节点
     * @param parent 父节点
     * @return 子节点
     */
    private static <T extends BaseTreeNode<?>> List<T> getCurrentNodeChildren(BaseTreeNode<?> parent, List<BaseTreeNode<?>> all) {
        // 判断当前节点有没有子节点, 没有则创建一个空长度的 List, 有就使用之前已有的所有子节点.
        List<T> childList = parent.getChildren() == null ? new ArrayList<>() : (List<T>) parent.getChildren();

        // 从 "待用菜单列表" 中找到当前节点的所有子节点
        for (BaseTreeNode<?> child : all) {
            if (parent.getId().equals(child.getParentId())) {
                childList.add((T) child);
            }
        }

        // 将当前节点的所有子节点从 "待用菜单列表" 中删除
        all.removeAll(childList);

        // 所有的子节点再寻找它们自己的子节点
        for (BaseTreeNode<?> menuTreeVO : childList) {
            menuTreeVO.setChildren(getCurrentNodeChildren(menuTreeVO, all));
        }
        return childList;
    }
}
